package com.iandun.web.framework.core.exception;

import com.iandun.web.framework.core.exception.customize.BusinessException;
import com.iandun.web.framework.core.http.Response;
import com.iandun.web.framework.core.http.ResponseStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.stream.Collectors;

/**
 * <h2>公共异常处理</h2>
 * <p>
 * 主要是为了解决异常在栈中不断传递的问题<br/>
 * 如果遇到了嵌套异常,链路特别长的话,最底层的发生异常就会不断的像上传递,所以这个切面对象的主要能力就是能够急事捕捉异常并且执行相关的策略
 * </p>
 *
 * @author :jason.liang
 * @date: 2021-05-19 17:00
 */
@Slf4j
@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    /**
     * 捕捉范围->全部异常
     */
    @ExceptionHandler(value = Exception.class)
    public Response<String> allExceptionHandler(Exception exception) {
        return GlobalControllerExceptionHandler.resolveExceptionCustom(exception);
    }

    public static Response resolveExceptionCustom(Throwable ex) {
        // 如果是普通业务异常
        if (ex instanceof BusinessException) {
            BusinessException businessException = (BusinessException) ex;
            return new Response<>(businessException.getErrCode(), businessException.getErrMsg());
        } else if (ex instanceof BindException) {
            // 参数绑定异常
            BindException bindException = (BindException) ex;
            String collect = bindException.getBindingResult()
                    .getFieldErrors()
                    .stream()
                    .map(DefaultMessageSourceResolvable::getDefaultMessage)
                    .collect(
                            Collectors.joining(",", "{", "}")
                    );
            Response<String> result =
                    new Response<>(ResponseStatus.INTERNAL_SERVER_ERROR.getCode(),
                            ResponseStatus.INTERNAL_SERVER_ERROR.getMsg());
            // 设置异常信息
            result.setData(collect);
            return result;
        } else if (ex instanceof MethodArgumentNotValidException) {
            BindingResult bindingResult
                    = ((MethodArgumentNotValidException) ex).getBindingResult();
            FieldError err = bindingResult.getFieldError();
            String message = "参数{".concat(err.getField()).concat("}").concat(err.getDefaultMessage());
            return new Response<>(ResponseStatus.BAD_REQUEST.getCode(), message);
        } else {
            log.error("resolveExceptionCustom error", ex);
            return new Response<>(ResponseStatus.INTERNAL_SERVER_ERROR.getCode(),
                    ResponseStatus.INTERNAL_SERVER_ERROR.getMsg());
        }
    }
}
